#! /usr/bin/python

__ALL__ = ["parse_input_file","conjunction", "atom_skeleton", "typed_list_x","typed_list_objects"]
from search import Problem
import Domain

import parse_domain
import parse_problem
import  PlanningProblem

#___________parsing file to a hierarchy of lists________
def parse_input_file(input_file): # return a generator
	tokens = tokenize(input_file)
	first_token = tokens.next()
	if first_token != "(":
		raise SyntaxError("Expected '(', got %s. Invalid STRIPS" % first_token)
	result = list(parse_sub_list(tokens))
	for token in tokens:  # Ensure no more tokens are left
		raise SyntaxError("Unexpected token: %s." % token)
	return result

def tokenize(input):
	for line in input:
		line = line.split(";", 1)[0]  # Removing comments
		line = line.replace("(", " ( ").replace(")", " ) ").replace("?", " ?") #format the code
		for token in line.split():
			yield token.lower()

def parse_sub_list(token_generator):
	# First "(" already removed by iterator so don't bother
	while True:
		token = token_generator.next()
		if token == ")":
			return
		elif token == "(":
			yield list(parse_sub_list(token_generator))
		else:
			yield token

#______________ Strip keywords, and keep only hierarchy list of values_______


# return list [(predicate1,[x*]), (predicate2,[x*]),.... ]
def conjunction(raw,x):
	l=[]
	if raw[0] == "and":
		l.extend( [x(a) for a in raw[1:]] )
	else: l.append(x(raw))
	return l


# return [ (name1,[tuple-vars1]), (name2,[tuple-vars2])...]
def atom_skeleton(predicates):
	l=[]
	for p in predicates:
		l.append( (p[0], typed_list_x(p[1:])) ) #  append a tuple
	return l


# return [(x1, type1), (x2,type2)...,(xn,typen)]
def typed_list_x(typed_list):
	#print typed_list
	l = []
	for i in typed_list:
		if type(i) is not str: raise SyntaxError("Error! parsing typed x")
		if i.find('?') == 0: # it is a variable
			x = i.replace('?','')
			x_type = ""
			#find x type
			x_passed = False
			for j in typed_list:
				if i == j: x_passed = True
				if x_passed and j != "-" and j.find('?') != 0: # gatcha
					x_type = j
					break
			if x_type == "" : raise SyntaxError("No Type!!")
			l.append( ( x, x_type) )

	return l

def typed_list_objects(typed_list):
	l = []
	while True:
		try:
			divider_index = typed_list.index("-")#Find the divider separating objects/constants values
			for obj in typed_list[:divider_index]:
				l.append((obj, typed_list[divider_index+1]))
			typed_list = typed_list[divider_index +2 :]
		except ValueError: break
	return l
# return (name1,[terms])
def atom(a):
	predicate = a[0]
	for i in xrange(len(a)):
		if a[i].find('?') == 0:
			a[i] = a[i].replace('?','')
	at = (predicate, a[1:])
	return  at
def literal(a):
	if a[0] == "not":
		return True,atom(a[1])
	else :
		return False,atom(a)

def loadIntoProblem(domainFile,problemFile):
	try:
		f = open(domainFile)
		listed_domain = parse_input_file(f)
		f.close()

		clean_domain_iterator = parse_domain.parseDomain(listed_domain)
		domain = Domain.Domain(clean_domain_iterator)

		f = open(problemFile)
		listed_problem = parse_input_file(f)
		f.close()
		clean_problem_iterator = parse_problem.parseProblem(listed_problem)
		problem = PlanningProblem.PlanningProblem(clean_problem_iterator, domain)

		return problem

	except Exception , msg:
		print "Error: ", msg

def print_save_path(n):
	if n is not None:
		print "writing to solution to solution.txt"
		f = open("solutions.txt", 'w')
		l = n.path()
		for p in l:
			f.write("%s"%p)
		f.close()
	else:
		print "No solution Found!!"

if __name__ == "__main__":
	from copy import deepcopy
	from search import *
	#problem = loadIntoProblem("pddl/domain1.pddl","pddl/problem1.pddl") #capture the error 
	#problem = loadIntoProblem("pddl/driverlog.pddl","pddl/driverproblem1.pddl")
	problem = loadIntoProblem("pddl/StripsRover.pddl","pddl/roverproblem1.pddl")
	#problem = loadIntoProblem("pddl/Depots.pddl","pddl/pfile1")
	n = depth_limited_search(problem)
	#n =iterative_deepening_search(problem)
	#n = breadth_first_graph_search(problem)
	print_save_path(n)


